#include "StdAfx.h"
#include "BattleGround.h"
#include "Actor.h"
#include "CommandConsts.h"
#include "CommandDispatcher.h"
#include "MemTrack.h"

namespace bs
{
	const int MIN_HP = 1;
	const int MIN_MP = 0;
	const int MIN_AT = 0;
	const int MIN_DF = 0;

	Actor::Actor(BattleGround& bg, bool isFriend) : bg(bg), isFriend(isFriend)
	{
	}

	Actor::~Actor()
	{
	}

	void Actor::Init(int hp, int mp, int at, int df, int attackStytle)
	{
		assert("Actor::Init" && attackStytle>=AT_MIN_HP && attackStytle<=AT_MAX_AT);

		this->hp = hp;
		this->mp = mp;
		this->at = at;
		this->df = df;
		this->as = attackStytle;

		if(this->hp < MIN_HP)
			this->hp = MIN_HP;

		if(this->mp < MIN_MP)
			this->mp = MIN_MP;

		if(this->at < MIN_AT)
			this->at = MIN_AT;

		if(this->df < MIN_DF)
			this->df = MIN_DF;
	}

	void Actor::SetImage(const char* file)
	{
		this->image.LoadFile(file, 1, 1);
		this->image.ShowFrame(0);
	}

	void Actor::Update()
	{
		this->CalcuMoveAndAttack();
	}

	void Actor::Draw(HDC dc)
	{
		if(!this->show)
			return;

		this->image.Draw(dc);
	}

	void Actor::Place(int dx, int dy)
	{
		assert("Actor::Place" && dx>=0 && dx<bg.GetCol() && dy>=0 && dy<bg.GetRow());

		this->pos.x = dx;
		this->pos.y = dy;

		this->bg.SetActor(this, this->pos);

		int xpos = this->bg.XIndexToCenterPos(this->pos.x);
		int ypos = this->bg.YIndexToCenterPos(this->pos.y);
		this->image.SetPos(xpos, ypos);

		Command* cmd = new Command(LGI_CMD, LG_ACTOR_PLACE);
		cmd->SetSrc(this);
		cmd->SetParam(&this->image);
		CommandDispatcher::Instance().SendCommand(cmd);
	}

	void Actor::MoveTo(Point to)
	{
		assert("Actor::MoveTo" && to.x>=0 && to.x<bg.GetCol() && to.y>=0 && to.y<bg.GetRow());

		Command* cmd = new Command(LGI_CMD, LG_ACTOR_MOVE);
		cmd->SetSrc(&this->pos);
		cmd->SetDst(&to);
		CommandDispatcher::Instance().SendCommand(cmd);

		this->bg.RemoveActor(this->pos);

		this->pos = to;

		this->bg.SetActor(this, pos);

		int xpos = this->bg.XIndexToCenterPos(this->pos.x);
		int ypos = this->bg.YIndexToCenterPos(this->pos.y);
		this->image.SetPos(xpos, ypos);
	}

	bool Actor::Attack(Actor* other)
	{
		int damage = this->at/* - other->df*/;

		if(damage <= 0)
			damage = 1;

		other->hp -= damage;

		int preAnimId = -1;
		Command* cmd = new Command(LGI_CMD, LG_ACTOR_ATTACK);
		cmd->SetDst(other);
		cmd->SetValue(damage);
		cmd->SetResult(&preAnimId);
		CommandDispatcher::Instance().SendCommand(cmd);

		// now, the cmd's result have the last anim id
		cmd = new Command(LGI_CMD, LG_ACTOR_DAMAGE);
		cmd->SetDst(other);
		cmd->SetValue(damage);
		cmd->SetResult(&preAnimId);
		CommandDispatcher::Instance().SendCommand(cmd);

		return (other->hp <= 0);
	}

	void Actor::SetShow(bool _show)
	{
		this->show = _show;

		if(this->show)
		{
			this->image.ShowFrame(0);
		}
	}

	void Actor::CalcuMoveAndAttack()
	{
		this->moveables.clear();
		this->attackables.clear();

		Actor* actor = NULL;

		if(pos.x-1 >= 0)
		{
			actor = this->bg.GetActor(pos.x-1, pos.y);
			if(!actor)
			{
				this->moveables.push_back(Point(pos.x-1, pos.y));
			}
			else if(actor->isFriend != this->isFriend)
			{
				this->attackables.push_back(Point(pos.x-1, pos.y));
			}
		}

		if(pos.x+1 < this->bg.GetCol())
		{
			actor = this->bg.GetActor(pos.x+1, pos.y);
			if(!actor)
			{
				this->moveables.push_back(Point(pos.x+1, pos.y));
			}
			else if(actor->isFriend != this->isFriend)
			{
				this->attackables.push_back(Point(pos.x+1, pos.y));
			}
		}

		if(pos.y+1 < this->bg.GetRow())
		{
			actor = this->bg.GetActor(pos.x, pos.y+1);
			if(!actor)
			{
				this->moveables.push_back(Point(pos.x, pos.y+1));
			}
			else if(actor->isFriend != this->isFriend)
			{
				this->attackables.push_back(Point(pos.x, pos.y+1));
			}
		}

		if(pos.y-1 >= 0)
		{
			actor = this->bg.GetActor(pos.x, pos.y-1);
			if(!actor)
			{
				this->moveables.push_back(Point(pos.x, pos.y-1));
			}
			else if(actor->isFriend != this->isFriend)
			{
				this->attackables.push_back(Point(pos.x, pos.y-1));
			}
		}
	}
}